/*
 * needlemanWunsch.cpp
 *
 *  Created on: 2011-09-10
 *      Author: pawel
 */
#include"needlemanWunsch.h"
#include"../enumTypes.h"
#include"../scoreMatrix.h"
#include"../smart2DArray.h"
#include<Bpp/Seq/Sequence.h>
#include"../algorithms.h"
#include<sys/param.h>
#include<stdio.h>
//#define MAX(a, b) (((a) > (b)) ? (a) : (b))
//#include<iostream>
//#include"../PerlComp/ProteicAlphabetPerl.h"
std::list<cell> needlemanWunsch::run(const optAlgParam &param){
	std::list<cell> alList;
	cell alCell;
	alCell.maxscore = INT_MIN;
	int **scoreMatrix = NULL;
	int **E = NULL;
	int **F = NULL;
	int EFinit = INT_MIN + param.gopen +param.gext;
	alCell.maxRow = param.dirMatrix.rows -1;
	alCell.maxCol = param.dirMatrix.cols -1;
	try{
		smart2DArray<int> smartScoreMAtrix(param.dirMatrix.rows,param.dirMatrix.cols);
		smart2DArray<int> smartE(param.dirMatrix.rows,param.dirMatrix.cols);
		smart2DArray<int> smartF(param.dirMatrix.rows,param.dirMatrix.cols);
		scoreMatrix = smartScoreMAtrix.getPtr();
		E = smartE.getPtr();
		F = smartF.getPtr();
		/*
		 * Matrix initialization
		 */
		scoreMatrix[0][0] = 0;
		for(size_t i=1;i<param.dirMatrix.rows;i++){
			scoreMatrix[i][0] = (int)(-param.gext*i - param.gopen);
			E[i][0] = EFinit;
			F[i][0] = EFinit;
		}
		for(size_t i =1;i<param.dirMatrix.cols;i++){
			scoreMatrix[0][i] = (int)(-param.gext*i - param.gopen);
			E[0][i] = EFinit;
			F[0][i] = EFinit;
		}

		smart2DArray<int> smartQueryCString(1,param.dirMatrix.rows);
		int *queryCString =(smartQueryCString.getPtr())[0];
		smart2DArray<int> smartDbCString(1,param.dirMatrix.cols);
		int *dbCString = (smartDbCString.getPtr())[0];

		memcpy((void*)queryCString,&(param.querySeqPtr->getContent()[0]),(param.querySeqPtr->getContent()).size() * sizeof(int));
		memcpy((void*)dbCString,&(param.dbSeqPtr->getContent()[0]),(param.dbSeqPtr->getContent()).size() * sizeof(int));
	//queryStr = rows
		int diag,up,left,mScore;

		char **matrix;
		matrix = param.scoreMatrixPtr->getMatrix();
		for(size_t i =1;i<param.dirMatrix.rows;i++){

			for(size_t j=1;j<param.dirMatrix.cols;j++){

				E[i][j] = MAX(E[i][j-1] - param.gext, scoreMatrix[i][j-1] -param.gopen);
				F[i][j] = MAX(F[i -1][j] - param.gext, scoreMatrix[i - 1][j] -param.gopen);

				//mScore = param.scoreMatrixPtr->getScore(queryCString[i-1],dbCString[j-1]);
				mScore = matrix[queryCString[i-1]][dbCString[j-1]];
				diag 	= scoreMatrix[i-1][j-1] + mScore;
				up		= F[i][j];
				left	= E[i][j];

				scoreMatrix[i][j] = MAX(diag,MAX(up,left));

				if(queryCString[i-1] == dbCString[j-1] ){
					param.dirMatrix.matrix[i][j]|= DR_IDENTITY;
				}
				else if(mScore > 0){
					param.dirMatrix.matrix[i][j]|= DR_MATCH;
				}
				else{
					param.dirMatrix.matrix[i][j]|= DR_MISMATCH;
				}
				if( scoreMatrix[i][j]>=alCell.maxscore){
					alCell.maxRow = i;
					alCell.maxCol = j;
					alCell.maxscore = scoreMatrix[i][j];
				}

				if(scoreMatrix[i][j] == diag){
					param.dirMatrix.matrix[i][j]|= DR_DIAG;
				}
				if(scoreMatrix[i][j] == up){
					param.dirMatrix.matrix[i][j]|= DR_UP;
				}
				if(scoreMatrix[i][j] == left){
					param.dirMatrix.matrix[i][j]|= DR_LEFT;
				}
			}
		}

		alList.push_front(alCell);

//		for(size_t i=0;i<param.dirMatrix.rows;i++){
//
//			for(size_t j=0;j<param.dirMatrix.cols;j++){
//				printf("\t %i",scoreMatrix[i][j]);
//			}
//			printf("\n");
//		}

	}catch(std::bad_alloc& e){
		throw;
		}

return alList;
}

needlemanWunsch::~needlemanWunsch()
{
}


